/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.cx1.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.cx1.dao.api.IFeaturedDao;
import org.cx1.dao.impl.FeaturedDao;
import org.cx1.model.Featured;
import org.cx1.model.FeaturedList;
import org.cx1.model.FurnishType;
import org.cx1.model.Listing;
import org.cx1.model.PropertyType;
import org.cx1.model.utils.RateUtils;
import org.cx1.model.utils.SearchOption;
import org.cx1.model.utils.ServiceResponse;
import org.cx1.model.utils.SystemProperties;
import org.cx1.service.api.IFeaturedService;
import org.cx1.service.api.IListingService;
import org.cx1.service.utils.IDGenerator;

/**
 *
 * @author ECH
 */
public class DFeaturedService implements IFeaturedService {

    private IFeaturedDao featuredDao = new FeaturedDao();
    private IListingService listingService = new DListingService();
    
    @Override
    public ServiceResponse<List<Listing>> randomFeaturedListings(String city, String termType, int max, SearchOption option) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> filteredListings = new ArrayList<Listing>();
        
        response.setResponse(filteredListings);
        try {            
            
            ServiceResponse<List<Listing>> response1 = this.randomFeaturedListings(city, termType, max);
            List<Listing> listings = response1.getResponse();
            
            if (listings != null && listings.size() > 0) {
                List<Listing> filtered = new ArrayList<Listing>();
                
                
                //CX: Filter property types
                if (option.getPropertyTypes() == null || option.getPropertyTypes().size() == 0) {
                    filtered.addAll(listings);
                }
                else {
                    for (PropertyType propertyTypes : option.getPropertyTypes()) {                        
                        for (Listing listing : listings) {
                            if (StringUtils.equalsIgnoreCase(propertyTypes.getId(), listing.getPropertyTypeID())) {
                                filtered.add(listing);
                            }
                        }                        
                    }  
                }                     
                listings.clear();
                listings.addAll(filtered);
                filtered.clear();
                
                //CX: Filter furnishings
                if (option.getFurnishTypes() == null || option.getFurnishTypes().size() == 0) {
                    filtered.addAll(listings);
                }
                else {
                    for (FurnishType furnishType : option.getFurnishTypes()) {                        
                        for (Listing listing : listings) {
                            if (StringUtils.equalsIgnoreCase(furnishType.getId(), listing.getFurnishTypeID())) {
                                filtered.add(listing);
                            }
                        }                        
                    }  
                }                     
                listings.clear();
                listings.addAll(filtered);
                filtered.clear();
                
                //CX: Filter bedrooms
                for (Listing listing : listings) {
                    if (listing.getNumBedrooms() >= option.getListingFilter().getNumBedroomsLow() &&
                        listing.getNumBathrooms() <= option.getListingFilter().getNumBedroomsHigh()    ) {
                        filtered.add(listing);
                    }
                }   
                listings.clear();
                listings.addAll(filtered);
                filtered.clear();
                
                //CX: Filter short day rate
                for (Listing listing : listings) {
                    if (listing.getShortDayRateNum() >= RateUtils.strRateToNum(option.getListingFilter().getShortDayRateLow()) &&
                        listing.getShortDayRateNum() <= RateUtils.strRateToNum(option.getListingFilter().getShortDayRateHigh()))  {
                        filtered.add(listing);
                    }
                }   
                listings.clear();
                listings.addAll(filtered);
                filtered.clear();
                
                //CX: Filter long month rate
                for (Listing listing : listings) {
                    if (listing.getLongMonthRateNum() >= RateUtils.strRateToNum(option.getListingFilter().getLongMonthRateLow()) &&
                        listing.getLongMonthRateNum() <= RateUtils.strRateToNum(option.getListingFilter().getLongMonthRateHigh()))  {
                        filtered.add(listing);
                    }
                }   
                listings.clear();
                listings.addAll(filtered);
                filtered.clear();
            }
            
            filteredListings.addAll(listings);
            
            //CX: increment impressions
            if (filteredListings != null && filteredListings.size() > 0) {  
                //CX: increment impression
                for (Listing listing : filteredListings) {
                    ServiceResponse<Boolean> response2 = listingService.incrementImpressions(listing.getId());                    
                }
            }
            
            response.setResponse(filteredListings);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(filteredListings);
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);    
        }
        return response; 
    }
    
    @Override
    public ServiceResponse<List<Listing>> randomFeaturedListings(String city, String termType, int max) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> listings = new ArrayList<Listing>();
        try {            
            ServiceResponse<List<Featured>> response1 = this.randomFeatured(city, termType, max);
            List<Featured> featureds = response1.getResponse();
            
            if (featureds != null && featureds.size() > 0) {
                for (Featured featured : featureds) {
                    ServiceResponse<Listing> response2 = listingService.read(featured.getListingID());
                    Listing listing = response2.getResponse();
                    
                    if (listing != null) {
                        listings.add(listing);
                    }
                }
            }
            
            response.setResponse(this.trimListingsData(listings));
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);    
        }
        return response; 
    }
    
    @Override
    public ServiceResponse<List<Featured>> randomFeatured(String city, String termType, int max) {
        ServiceResponse<List<Featured>> response = new ServiceResponse<List<Featured>>();
        List<Featured> randoms = new ArrayList<Featured>();
        try {            
            ServiceResponse<List<Featured>> response1 = this.readAll(city, termType, 0, 0);
            List<Featured> featureds = response1.getResponse();
            
            if (featureds != null && featureds.size() > 0) {                
                int size = response1.getResponse().size();
                if (max >= size) {
                    randoms.addAll(featureds);
                }
                else {
                    Set<Integer> indexes = getRandomIndexes(featureds.size(), max);
                    for (int index : indexes) {
                        randoms.add(featureds.get(index));
                    }
                }
            }
            response.setResponse(randoms);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);    
        }
        return response; 
    }
    
    public Set<Integer> getRandomIndexes(int length, int max) {
        Set<Integer> indexSet = new HashSet();
        while (indexSet.size() < max) {
            indexSet.add(randInt(0, length-1));
        }
        return indexSet;
    }
    
    public static int randInt(int min, int max) {
        Random rand = new Random();
        int randomNum = rand.nextInt((max - min) + 1) + min;
        return randomNum;
    }
    
    
    @Override
    public ServiceResponse<String> create(Featured featured) {
        ServiceResponse<String> response = new ServiceResponse<String>();
        String id = null;        
        try {            
            Featured entry = new Featured();
            id = IDGenerator.generateID();
                        
            entry.setId(id);
            entry.setType(featured.getType());
            
            entry.setTermType(featured.getTermType());            
            entry.setListingID(featured.getListingID());
            entry.setCity(featured.getCity());       
            
            entry.setStartDate(featured.getStartDate());
            entry.setEndDate(featured.getEndDate());
            
            entry.setStrStartDate(featured.getStrStartDate());
            entry.setStrEndDate(featured.getStrEndDate());
            
            entry.setActive(true);
            entry.setDateCreated(new Date());
            entry.setDateModified(new Date());
                        
            featuredDao.add(entry);
            
            response.setResponse(id);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse("");
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    
    @Override
    public ServiceResponse<List<Featured>> readAll(int offset, int limit) {
        ServiceResponse<List<Featured>> response = new ServiceResponse<List<Featured>>();
        List<Featured> featureds = new ArrayList<Featured>();        
        try {            
            List<Featured> records = featuredDao.getAll();
            //CX: transfer
            if (records != null && records.size() > 0) {
                featureds.addAll(records);                
            }
            response.setResponse(featureds);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);    
        }
        return response; 
    }
    
    @Override
    public ServiceResponse<List<Featured>> readAll(String city, String termType, int offset, int limit) {
        ServiceResponse<List<Featured>> response = new ServiceResponse<List<Featured>>();
        Set<Featured> featuredsSet = new HashSet<Featured>();
        List<Featured> featureds = new ArrayList<Featured>();
        try {            
            List<Featured> records = featuredDao.getAll();
            
            //CX: filter city
            if (records != null && records.size() > 0) {
                for (Featured record : records) {
                    if (StringUtils.equalsIgnoreCase(city, record.getCity()) &&
                        StringUtils.equalsIgnoreCase(termType, record.getTermType())) {
                        featuredsSet.add(record);
                    }
                }
            }
                      
            //CX: transfer
            if (featuredsSet != null && featuredsSet.size() > 0) {
                featureds.addAll(featuredsSet);                
            }
            response.setResponse(featureds);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);    
        }
        return response; 
    }

    @Override
    public ServiceResponse<Boolean> delete(String id) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {            
            featuredDao.deleteById(id);
            success = true;
            response.setResponse(success);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<List<FeaturedList>> readAllFeaturedList(int offset, int limit) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public ServiceResponse<String> createFeaturedList(String id, FeaturedList featuredList) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public ServiceResponse<Boolean> deleteFeaturedList(String id) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public ServiceResponse<Boolean> checkMaxReached(String city, String termType) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean maxReached = false;
        try {            
            ServiceResponse<List<Featured>> response1 = this.readAll(city, termType, 0, 0);
            List<Featured> currentFeatureds = response1.getResponse();                
            if (currentFeatureds != null && currentFeatureds.size() >= SystemProperties.FEATURED_LISTING_MAX) {
                maxReached = true;
            }
            response.setResponse(maxReached);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<Boolean> checkExisting(String listingID, String city, String termType) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean exisiting = false;
        try {            
            ServiceResponse<List<Featured>> response2 = this.readAll(city, termType, 0, 0);
            List<Featured> currentFeatureds2 = response2.getResponse(); 
            
            if (currentFeatureds2 != null && currentFeatureds2.size() > 0) {
                for (Featured featured2 : currentFeatureds2) {
                    if (StringUtils.equalsIgnoreCase(featured2.getListingID(), listingID) &&
                        StringUtils.equalsIgnoreCase(featured2.getCity(), city) && 
                        StringUtils.equalsIgnoreCase(featured2.getTermType(), termType) ) {
                        exisiting = true;
                        break;
                    }
                }
            }   
            response.setResponse(exisiting);
            response.setSuccessful(true);
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }

    @Override
    public ServiceResponse<Boolean> checkListingValid(String listingID) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean valid = false;
        try {            
            ServiceResponse<Listing> response1 = this.listingService.read(listingID);
            Listing listing = response1.getResponse();
            
            if (listing.isVerified() && !listing.isPenalized()) {
                valid = true;
            }
            response.setResponse(valid);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }

    
    private List<Listing> trimListingsData(List<Listing> listings) {
        List<Listing> trimmedListings = new ArrayList<Listing>();
        if (listings != null && listings.size() > 0) {
            
            for (Listing listing : listings) {
                Listing trimmed = new Listing();
                trimmed.setId(listing.getId());
                trimmed.setTitle(listing.getTitle());
                trimmed.setDisplayTitle(listing.getDisplayTitle());
                trimmed.setUrlTitle(listing.getUrlTitle());
                trimmed.setAddress(listing.getAddress());
                trimmed.setPrimaryPhoto(listing.getPrimaryPhoto());
                trimmed.setSqArea(listing.getSqArea());
                trimmed.setLongMonthRate(String.format("%,.0f", listing.getLongMonthRateNum()));
                trimmed.setShortDayRate(String.format("%,.0f", listing.getShortDayRateNum()));
                trimmed.setShortWeekRate(String.format("%,.0f", listing.getShortWeekRateNum()));
                trimmed.setShortMonthRate(String.format("%,.0f", listing.getShortMonthRateNum()));
                trimmed.setAvailable(listing.isAvailable());
                trimmed.setLeaseLongTerm(listing.isLeaseLongTerm());
                trimmed.setLeaseShortTerm(listing.isLeaseShortTerm());
                trimmed.setCommunity(listing.getCommunity());
                trimmed.setCity(listing.getCity());
                trimmedListings.add(trimmed);
            }
        }
        return trimmedListings;
    }
    
}
